// Package web
// Created by GoLand
// @User: lenora
// @Date: 2024/1/17
// @Time: 12:42

package web

import (
	intrv1 "camp/microbook/api/proto/gen/interactive"
	"camp/microbook/internal/domain"
	"camp/microbook/internal/service"
	ijwt "camp/microbook/internal/web/jwt"
	"camp/microbook/pkg/logger"
	"github.com/gin-gonic/gin"
	"golang.org/x/sync/errgroup"
	"strconv"
)

type ArticleHandler struct {
	svc      service.ArticleService
	interSvc intrv1.InteractiveServiceClient
	l        logger.Logger
	biz      string
}

func NewArticleHandler(svc service.ArticleService, client intrv1.InteractiveServiceClient, log logger.Logger) *ArticleHandler {
	return &ArticleHandler{
		svc:      svc,
		interSvc: client,
		l:        log,
		biz:      "article",
	}

}

func (h *ArticleHandler) RegisterRoutes(engine *gin.Engine) {
	g := engine.Group("/article/")
	{
		g.POST("edit", h.Edit)
		g.POST("withdraw", h.Withdraw)

		//创作者接口
		g.GET("detail/:id", h.Detail)
		g.GET("list", h.List)

		//读者接口
		pub := g.Group("pub/")
		pub.GET(":id", h.PubDetail)
		pub.POST("like", h.Like)
		pub.POST("collect", h.Collect)
	}
}

func (h *ArticleHandler) Edit(ctx *gin.Context) {
	type articleReq struct {
		Id      uint64 `json:"id"`
		Title   string `json:"title"`
		Content string `json:"content"`
	}
	var req articleReq
	if err := ctx.BindJSON(&req); err != nil {
		webResp.InvalidParametersError(ctx)
		return
	}

	uc := ctx.MustGet("web").(ijwt.UserClaims)
	id, err := h.svc.Save(ctx.Request.Context(), domain.Article{
		Id:      req.Id,
		Title:   req.Title,
		Content: req.Content,
		Author: domain.Author{
			Id: uc.Id,
		},
	})
	if err != nil {
		webResp.InternalServiceError(ctx, err.Error())
		return
	}
	webResp.ResponseSuccess(ctx, id)
}

func (h *ArticleHandler) Withdraw(ctx *gin.Context) {
	var req struct {
		Id uint64
	}
	if err := ctx.Bind(&req); err != nil {
		webResp.InvalidParametersError(ctx)
		return
	}

	uc := ctx.MustGet("web").(ijwt.UserClaims)
	err := h.svc.Withdraw(ctx.Request.Context(), uc.Id, req.Id)
	if err != nil {
		webResp.InternalServiceError(ctx, err.Error())
		return
	}
	webResp.ResponseSuccess(ctx, nil)
}

func (h *ArticleHandler) Detail(ctx *gin.Context) {
	idStr := ctx.Param("id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		webResp.InvalidParametersError(ctx)
	}
	res, err := h.svc.GetById(ctx.Request.Context(), id)
	if err != nil {
		webResp.InternalServiceError(ctx, err.Error())
		return
	}
	uc := ctx.MustGet("web").(ijwt.UserClaims)
	if res.Author.Id != uc.Id {
		h.l.Error("the item is not belong to this author")
		webResp.InternalServiceError(ctx, err.Error())
	}
	webResp.ResponseSuccess(ctx, res)
}

func (h *ArticleHandler) List(ctx *gin.Context) {
	var page Page
	if err := ctx.Bind(&page); err != nil {
		webResp.InvalidParametersError(ctx)
		return
	}
	uc := ctx.MustGet("web").(ijwt.UserClaims)
	arts, err := h.svc.GetByAuthor(ctx.Request.Context(), uc.Id, page.Offset, page.Limit)
	if err != nil {
		webResp.InternalServiceError(ctx, err.Error())
		return
	}
	webResp.ResponseSuccess(ctx, arts)
}

func (h *ArticleHandler) PubDetail(ctx *gin.Context) {
	idStr := ctx.Param("id")
	id, iErr := strconv.ParseUint(idStr, 10, 64)
	if iErr != nil {
		webResp.InvalidParametersError(ctx)
	}
	uc := ctx.MustGet("web").(ijwt.UserClaims)
	var (
		res domain.Article
		err error
		eg  errgroup.Group
	)

	//获取文章基本信息
	eg.Go(func() error {
		var dErr error
		res, dErr = h.svc.GetPubById(ctx.Request.Context(), id, uc.Id)
		return dErr
	})

	eg.Go(func() error {
		intr, iErr := h.interSvc.Get(ctx.Request.Context(), &intrv1.GetReq{
			Biz:    h.biz,
			Id:     id,
			UserId: uc.Id,
		})
		res.Interactive = intr.Interactive
		return iErr
	})
	err = eg.Wait()
	if err != nil {
		webResp.InternalServiceError(ctx, err.Error())
		return
	}

	//增加阅读数
	//go func() {
	//	// 1. 如果你想摆脱原本主链路的超时控制，你就创建一个新的
	//	// 2. 如果你不想，你就用 ctx
	//	newCtx, cancel := context.WithTimeout(context.Background(), time.Second)
	//	defer cancel()
	//	readErr := h.interSvc.IncrReadCnt(newCtx, h.biz, id)
	//	if readErr != nil {
	//		h.l.Error("incr read cnt error",
	//			logger.Uint64("bizId", id),
	//			logger.Error(readErr),
	//		)
	//	}
	//}()
	webResp.ResponseSuccess(ctx, res)
	return

}

func (h *ArticleHandler) Like(ctx *gin.Context) {
	type likeReq struct {
		Id     uint64 `json:"id"`
		Status bool   `json:"status"` //是否点赞,true为点赞,false为取消点赞
	}
	var req likeReq
	if err := ctx.BindJSON(&req); err != nil {
		webResp.InvalidParametersError(ctx)
		return
	}
	uc := ctx.MustGet("web").(ijwt.UserClaims)
	var err error
	likeCntReq := &intrv1.LikeCntReq{
		Biz:    h.biz,
		Id:     req.Id,
		UserId: uc.Id,
	}
	if req.Status {
		_, err = h.interSvc.IncrLikeCnt(ctx.Request.Context(), likeCntReq)
	} else {
		_, err = h.interSvc.DecrLikeCnt(ctx.Request.Context(), likeCntReq)
	}
	if err != nil {
		h.l.Error("like/cancel like failed",
			logger.Error(err),
			logger.Uint64("id", req.Id),
		)
		webResp.InternalServiceError(ctx, err.Error())
		return
	}
	webResp.ResponseSuccess(ctx, nil)
	return
}

func (h *ArticleHandler) Collect(ctx *gin.Context) {
	type collectReq struct {
		Id  uint64 `json:"id"`
		Cid uint64 `json:"cid"` //收藏夹id
	}
	var req collectReq
	if err := ctx.BindJSON(&req); err != nil {
		webResp.InvalidParametersError(ctx)
		return
	}
	uc := ctx.MustGet("web").(ijwt.UserClaims)
	_, err := h.interSvc.Collect(ctx.Request.Context(), &intrv1.CollectReq{
		Biz:    h.biz,
		Id:     req.Id,
		Cid:    req.Cid,
		UserId: uc.Id,
	})

	if err != nil {
		h.l.Error("collect failed",
			logger.Error(err),
			logger.Uint64("id", req.Id),
		)
		webResp.InternalServiceError(ctx, err.Error())
		return
	}
	webResp.ResponseSuccess(ctx, nil)
	return
}
